/*
 *
 *  Copyright (C) 2012-2024
 *  All rights reserved, Designed By 杭州连线客信息技术有限公司
 *  注意：
 *  本软件为杭州连线客信息技术有限公司开发研制，未经购买不得使用
 *  购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 *  一经发现盗用、分享等行为，将追究法律责任，后果自负
 *
 */

package com.lxk.mall.pms.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lxk.mall.pms.convert.sku.ProductSkuConvert;
import com.lxk.mall.pms.domain.PmsProductProperty;
import com.lxk.mall.pms.domain.PmsProductPropertyValue;
import com.lxk.mall.pms.domain.PmsProductSku;
import com.lxk.mall.pms.domain.bo.spu.PmsProductSkuBo;
import com.lxk.mall.pms.domain.bo.spu.ProductSkuSaveReqBO;
import com.lxk.mall.pms.domain.bo.spu.ProductSkuUpdateStockReqBo;
import com.lxk.mall.pms.domain.vo.spu.PmsProductSkuVo;
import com.lxk.mall.pms.domain.vo.spu.ProductSkuPropertyVO;
import com.lxk.mall.pms.enums.PmsErrorCodeConstants;
import com.lxk.mall.pms.mapper.PmsProductSkuMapper;
import com.lxk.mall.pms.service.IPmsProductPropertyService;
import com.lxk.mall.pms.service.IPmsProductPropertyValueService;
import com.lxk.mall.pms.service.IPmsProductSkuService;
import com.lxk.mall.pms.service.IPmsProductSpuService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.CollectionUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 商品skuService业务层处理
 *
 * @author Lion Li
 * @date 2024-06-06
 */
@RequiredArgsConstructor
@Service
public class PmsProductSkuServiceImpl implements IPmsProductSkuService {

    private final PmsProductSkuMapper baseMapper;

    @Resource
    @Lazy // 循环依赖，避免报错
    private IPmsProductSpuService productSpuService;
    @Resource
    @Lazy // 循环依赖，避免报错
    private IPmsProductPropertyService productPropertyService;
    @Resource
    private IPmsProductPropertyValueService productPropertyValueService;

    /**
     * 查询商品sku
     *
     * @param id 主键
     * @return 商品sku
     */
    @Override
    public PmsProductSkuVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    @Override
    public PmsProductSkuVo queryByIdAndMerId(Long id, Long merId) {
        return baseMapper.selectVoOne(new LambdaQueryWrapper<PmsProductSku>().eq(PmsProductSku::getMerId, merId).eq(PmsProductSku::getId, id));
    }

    /**
     * 分页查询商品sku列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 商品sku分页列表
     */
    @Override
    public TableDataInfo<PmsProductSkuVo> queryPageList(PmsProductSkuBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PmsProductSku> lqw = buildQueryWrapper(bo);
        Page<PmsProductSkuVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的商品sku列表
     *
     * @param bo 查询条件
     * @return 商品sku列表
     */
    @Override
    public List<PmsProductSkuVo> queryList(PmsProductSkuBo bo) {
        LambdaQueryWrapper<PmsProductSku> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    /**
     * 查询IdList
     */
    @Override
    public List<PmsProductSkuVo> queryByIdList(List<Long> idList) {
        if (CollUtil.isEmpty(idList)) {
            return CollUtil.newArrayList();
        }
        LambdaQueryWrapper<PmsProductSku> lqw = Wrappers.lambdaQuery();
        lqw.in(PmsProductSku::getId, idList);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PmsProductSku> buildQueryWrapper(PmsProductSkuBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PmsProductSku> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getSpuId() != null, PmsProductSku::getSpuId, bo.getSpuId());
        lqw.eq(StringUtils.isNotBlank(bo.getProperties()), PmsProductSku::getProperties, bo.getProperties());
        lqw.eq(bo.getPrice() != null, PmsProductSku::getPrice, bo.getPrice());
        lqw.eq(bo.getMarketPrice() != null, PmsProductSku::getMarketPrice, bo.getMarketPrice());
        lqw.eq(bo.getCostPrice() != null, PmsProductSku::getCostPrice, bo.getCostPrice());
        lqw.eq(StringUtils.isNotBlank(bo.getBarCode()), PmsProductSku::getBarCode, bo.getBarCode());
        lqw.eq(StringUtils.isNotBlank(bo.getPicUrl()), PmsProductSku::getPicUrl, bo.getPicUrl());
        lqw.eq(bo.getStock() != null, PmsProductSku::getStock, bo.getStock());
        lqw.eq(bo.getWeight() != null, PmsProductSku::getWeight, bo.getWeight());
        lqw.eq(bo.getVolume() != null, PmsProductSku::getVolume, bo.getVolume());
        lqw.eq(bo.getFirstBrokeragePrice() != null, PmsProductSku::getFirstBrokeragePrice, bo.getFirstBrokeragePrice());
        lqw.eq(bo.getSecondBrokeragePrice() != null, PmsProductSku::getSecondBrokeragePrice, bo.getSecondBrokeragePrice());
        lqw.eq(bo.getSalesCount() != null, PmsProductSku::getSalesCount, bo.getSalesCount());
        return lqw;
    }

    /**
     * 新增商品sku
     *
     * @param bo 商品sku
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(PmsProductSkuBo bo) {
        PmsProductSku add = MapstructUtils.convert(bo, PmsProductSku.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改商品sku
     *
     * @param bo 商品sku
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(PmsProductSkuBo bo) {
        PmsProductSku update = MapstructUtils.convert(bo, PmsProductSku.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(PmsProductSku entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除商品sku信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public List<PmsProductSku> getSkuListBySpuId(Long spuId) {
        return baseMapper.selectListBySpuId(spuId);
    }

    @Override
    public List<PmsProductSkuVo> getSkuListBySpuId(List<Long> spuIdList) {
        return baseMapper.selectVoList(new LambdaQueryWrapper<PmsProductSku>().in(PmsProductSku::getSpuId, spuIdList));
    }

    @Override
    public PmsProductSku getSku(Long skuId) {
        return baseMapper.selectById(skuId);
    }

    @Override
    public void validateSkuList(List<ProductSkuSaveReqBO> skus, Integer specType) {
        // 0、校验skus是否为空
        if (CollUtil.isEmpty(skus)) {
            throw new ServiceException(PmsErrorCodeConstants.SKU_NOT_EXISTS);
        }
        // 单规格，赋予单规格默认属性
        if (ObjectUtil.equal(specType, 0)) {
            ProductSkuSaveReqBO skuVO = skus.get(0);
            List<ProductSkuPropertyVO> properties = new ArrayList<>();
            ProductSkuPropertyVO property = new ProductSkuPropertyVO();
            property.setPropertyId(PmsProductProperty.ID_DEFAULT);
            property.setPropertyName(PmsProductProperty.NAME_DEFAULT);
            property.setValueId(PmsProductProperty.ID_DEFAULT);
            property.setValueName(PmsProductProperty.NAME_DEFAULT);
            properties.add(property);
            skuVO.setProperties(properties);
            return; // 单规格不需要后续的校验
        }

        // 1、校验属性项存在
        Set<Long> propertyIds = skus.stream().filter(p -> p.getProperties() != null)
            // 遍历多个 Property 属性
            .flatMap(p -> p.getProperties().stream())
            // 将每个 Property 转换成对应的 propertyId，最后形成集合
            .map(ProductSkuPropertyVO::getPropertyId)
            .collect(Collectors.toSet());
        if (propertyIds.isEmpty()) {
            throw new ServiceException(PmsErrorCodeConstants.PROPERTY_NOT_EXISTS);
        }
        List<PmsProductProperty> propertyList = productPropertyService.getPropertyList(propertyIds);
        if (propertyList.size() != propertyIds.size()) {
            throw new ServiceException(PmsErrorCodeConstants.PROPERTY_NOT_EXISTS);
        }

        // 2. 校验，一个 SKU 下，没有重复的属性。校验方式是，遍历每个 SKU ，看看是否有重复的属性 propertyId
        Map<Long, PmsProductPropertyValue> propertyValueMap = CollectionUtils.convertMap(productPropertyValueService.getPropertyValueListByPropertyId(propertyIds), PmsProductPropertyValue::getId);
        skus.forEach(sku -> {
            Set<Long> skuPropertyIds = CollectionUtils.convertSet(sku.getProperties(), propertyItem -> {
                PmsProductPropertyValue pmsProductPropertyValue = propertyValueMap.get(propertyItem.getValueId());
                if (pmsProductPropertyValue == null) {
                    throw new ServiceException(PmsErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
                }
                return pmsProductPropertyValue.getPropertyId();
            });
            if (skuPropertyIds.size() != sku.getProperties().size()) {
                throw new ServiceException(PmsErrorCodeConstants.SKU_PROPERTIES_DUPLICATED);
            }
        });

        // 3. 再校验，每个 Sku 的属性值的数量，是一致的。
        int attrValueIdsSize = skus.get(0).getProperties().size();
        for (int i = 1; i < skus.size(); i++) {
            if (attrValueIdsSize != skus.get(i).getProperties().size()) {
                throw new ServiceException(PmsErrorCodeConstants.SPU_ATTR_NUMBERS_MUST_BE_EQUALS);
            }
        }

        // 4. 最后校验，每个 Sku 之间不是重复的
        // 每个元素，都是一个 Sku 的 attrValueId 集合。这样，通过最外层的 Set ，判断是否有重复的.
        Set<Set<Long>> skuAttrValues = new HashSet<>();
        for (ProductSkuSaveReqBO sku : skus) {
            // 添加失败，说明重复
            if (!skuAttrValues.add(CollectionUtils.convertSet(sku.getProperties(), ProductSkuPropertyVO::getValueId))) {
                throw new ServiceException(PmsErrorCodeConstants.SPU_SKU_NOT_DUPLICATE);
            }
        }
    }

    @Override
    public void createSkuList(Long spuId, List<ProductSkuSaveReqBO> skuSaveReqList) {
        List<PmsProductSku> skus = MapstructUtils.convert(skuSaveReqList, PmsProductSku.class, (source, dest) -> {
            dest.setSpuId(spuId);
        });
        baseMapper.insertBatch(skus);
    }

    @Override
    public int updateSkuProperty(Long propertyId, String propertyName) {
        // 获取所有的 sku
        List<PmsProductSku> skuDOList = baseMapper.selectList();
        // 处理后需要更新的 sku
        List<PmsProductSku> updateSkus = new ArrayList<>();
        if (CollUtil.isEmpty(skuDOList)) {
            return 0;
        }
        skuDOList.stream().filter(sku -> sku.getProperties() != null)
            .forEach(sku -> {
                String properties = sku.getProperties();
                List<ProductSkuPropertyVO> skuProperties = JsonUtils.parseArray(properties, ProductSkuPropertyVO.class);
                skuProperties.forEach(property -> {
                    if (property.getPropertyId().equals(propertyId)) {
                        property.setPropertyName(propertyName);
                        updateSkus.add(sku);
                    }
                });
            });
        if (CollUtil.isEmpty(updateSkus)) {
            return 0;
        }
        baseMapper.updateBatchById(updateSkus);
        return updateSkus.size();
    }

    @Override
    public boolean updateSkuPropertyValue(Long propertyValueId, String propertyValueName) {
        // 获取所有的 sku
        List<PmsProductSku> skuDOList = baseMapper.selectList();
        // 处理后需要更新的 sku
        List<PmsProductSku> updateSkus = new ArrayList<>();
        if (CollUtil.isEmpty(skuDOList)) {
            return true;
        }
        skuDOList.stream().filter(sku -> sku.getProperties() != null)
            .forEach(sku -> {
                String properties = sku.getProperties();
                List<ProductSkuPropertyVO> skuProperties = JsonUtils.parseArray(properties, ProductSkuPropertyVO.class);
                skuProperties.forEach(property -> {
                    if (property.getValueId().equals(propertyValueId)) {
                        property.setValueName(propertyValueName);
                        updateSkus.add(sku);
                    }
                });
            });
        if (CollUtil.isEmpty(updateSkus)) {
            return true;
        }

        return baseMapper.updateBatchById(updateSkus);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSkuList(Long spuId, List<ProductSkuSaveReqBO> skus) {
        // 构建属性与 SKU 的映射关系;
        List<PmsProductSku> skuList = baseMapper.selectListBySpuId(spuId);
        Map<String, Long> existsSkuMap = CollectionUtils.convertMap(skuList, ProductSkuConvert.INSTANCE::buildPropertyKey, PmsProductSku::getId);
        // 拆分三个集合，新插入的、需要更新的、需要删除的
        List<PmsProductSku> insertSkus = new ArrayList<>();
        List<PmsProductSku> updateSkus = new ArrayList<>();
        List<PmsProductSku> allUpdateSkus = MapstructUtils.convert(skus, PmsProductSku.class, (source, dest) -> dest.setSpuId(spuId));
        allUpdateSkus.forEach(sku -> {
            String propertiesKey = ProductSkuConvert.INSTANCE.buildPropertyKey(sku);
            // 1、找得到的，进行更新
            Long existsSkuId = existsSkuMap.remove(propertiesKey);
            if (existsSkuId != null) {
                sku.setId(existsSkuId);
                updateSkus.add(sku);
                return;
            }
            // 2、找不到，进行插入
            sku.setSpuId(spuId);
            insertSkus.add(sku);
        });

        // 执行最终的批量操作
        if (CollUtil.isNotEmpty(insertSkus)) {
            baseMapper.insertBatch(insertSkus);
        }
        if (CollUtil.isNotEmpty(updateSkus)) {
            updateSkus.forEach(sku -> baseMapper.updateById(sku));
        }
        if (CollUtil.isNotEmpty(existsSkuMap)) {
            baseMapper.deleteBatchIds(existsSkuMap.values());
        }
    }

    @Override
    public void updateSkuStock(ProductSkuUpdateStockReqBo updateStockReqDTO) {
        // 更新 SKU 库存
        updateStockReqDTO.getItems().forEach(item -> {
            if (item.getIncrCount() > 0) {
                baseMapper.updateStockIncr(item.getId(), item.getIncrCount());
            } else if (item.getIncrCount() < 0) {
                int updateStockIncr = baseMapper.updateStockDecr(item.getId(), item.getIncrCount());
                if (updateStockIncr == 0) {
                    throw new ServiceException(PmsErrorCodeConstants.SKU_STOCK_NOT_ENOUGH);
                }
            }
        });

        // 更新 SPU 库存
        List<PmsProductSku> skus = baseMapper.selectBatchIds(
            CollectionUtils.convertSet(updateStockReqDTO.getItems(), ProductSkuUpdateStockReqBo.Item::getId));
        Map<Long, Integer> spuStockIncrCounts = ProductSkuConvert.INSTANCE.convertSpuStockMap(
            updateStockReqDTO.getItems(), skus);
        productSpuService.updateSpuStock(spuStockIncrCounts);
    }

    @Override
    public List<PmsProductSkuVo> queryBatchByIds(Set<Long> ids) {
        //判断ids是否为空
        if (CollUtil.isNotEmpty(ids)) {
            //查询sku
            return baseMapper.selectVoByIds(ids, PmsProductSkuVo.class);
        }
        return List.of();
    }

    @Override
    public int lockStockBySkuId(Long id, Integer count) {
        return baseMapper.lockStockBySkuId(id, count);
    }
}
